home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Leser 19 / Amiga Plus Leser CD 19.iso / Tools / MorphOS / cvs-1.11.2 / source / amiga / ssh / ssh_protocol.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-11-18  |  23.7 KB  |  1,082 lines

  1. /*
  2.  * $Id$
  3.  *
  4.  * :ts=4
  5.  *
  6.  * This implementation is based upon the 'dossh' code which is
  7.  * Copyright (c) 2000 by Nagy Daniel. It was 'condensed' and
  8.  * adapted for use with the Amiga port of CVS 1.11 by
  9.  * Olaf Barthel <olsen@sourcery.han.de> and
  10.  * Jens Langner <Jens.Langner@light-speed.de>
  11.  *
  12.  * While some of this code is Amiga-specific, namely the use of the
  13.  * shared 'bsdsocket.library', it is quite portable all in itself.
  14.  * Just remove those Amiga-specific header files and you should be
  15.  * able to use this code in just about any other configuration.
  16.  *
  17.  *
  18.  * This program is free software; you can redistribute it and/or
  19.  * modify it under the terms of the GNU General Public License
  20.  * as published by the Free Software Foundation; either version 2
  21.  * of the License, or (at your option) any later version.
  22.  *
  23.  * This program is distributed in the hope that it will be useful,
  24.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  25.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26.  * GNU General Public License for more details.
  27.  *
  28.  * You should have received a copy of the GNU Library General Public
  29.  * License along with this program; if not, write to the Free Software
  30.  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  31.  */
  32.  
  33. #ifdef AMIGA
  34.  
  35. #include <pwd.h>
  36.  
  37. #include <proto/bsdsocket.h>
  38.  
  39. #include <devices/timer.h>
  40.  
  41. #define select(num_fds,read_fds,write_fsd,except_fsd,timeval) \
  42.     WaitSelect(num_fds,read_fds,write_fsd,except_fsd,timeval,NULL)
  43.  
  44. char *amiga_strerror(int n);
  45.  
  46. #define strerror(n) amiga_strerror(n)
  47.  
  48. #endif /* AMIGA */
  49.  
  50. #include <time.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54.  
  55. #include <errno.h>
  56.  
  57. /****************************************************************************/
  58.  
  59. #include "ssh.h"
  60. #include "md5.h"
  61. #include "rsa.h"
  62. #include "des.h"
  63. #include "crc.h"
  64. #include "macros.h"
  65. #include "blowfish.h"
  66. #include "ssh_protocol.h"
  67.  
  68. /****************************************************************************/
  69.  
  70. #define SSH_VERSION "0.8"
  71.  
  72. /****************************************************************************/
  73.  
  74. static int recv_all(int socket, void *data, int len);
  75. static int sock_gets(int sock, char *buf, int n);
  76. static int check_emulation(int remote_major, int remote_minor, int *return_major, int *return_minor);
  77. static int exchange_identification(struct ssh_protocol_context *spc);
  78. static int create_keys(struct ssh_protocol_context *spc);
  79. static int send_password(struct ssh_protocol_context *spc, char *password);
  80. static int set_maximum_packet_size(struct ssh_protocol_context *spc);
  81. static int convert_received_data(struct ssh_protocol_context *spc);
  82. static void prepare_packet_header(struct ssh_protocol_context *spc, int type, int len);
  83. static int write_packet(struct ssh_protocol_context *spc);
  84. static int read_packet(struct ssh_protocol_context *spc);
  85. static int read_packet_and_check_type(struct ssh_protocol_context *spc, int type);
  86. static int send_ssh_data(struct ssh_protocol_context *spc, int type, void *data, int len);
  87.  
  88. /****************************************************************************/
  89.  
  90. /* Parameters of a pseudo-random-number generator from Knuth's
  91.  * "The Art of Computer Programming, Volume 2: Seminumerical
  92.  *  Algorithms" (3rd edition), pp. 185-186.
  93.  */
  94. #define MM 2147483647    /* a Mersenne prime */
  95. #define AA 48271        /* this does well in the spectral test */
  96. #define QQ 44488        /* (long)(MM/AA) */
  97. #define RR 3399            /* MM % AA; it is important that RR < QQ */
  98.  
  99. long
  100. get_random_number(void)
  101. {
  102.     static long X;
  103.  
  104.     /* This seeds the random number generator; X is never zero. */
  105.     if(X == 0)
  106.         X = (long)time(NULL);
  107.  
  108.     X = AA * (X % QQ) - RR * (long)(X / QQ);
  109.     if(X < 0)
  110.         X += MM;
  111.  
  112.     return(X);
  113. }
  114.  
  115. /****************************************************************************/
  116.  
  117. /* A variation of 'recv()' which will attempt to satisfy the
  118.  * entire read request.
  119.  */
  120. static int
  121. recv_all(int socket,void * data,int len)
  122. {
  123.     unsigned char * m = data;
  124.     int total = 0;
  125.     int n;
  126.  
  127.     while(len > 0)
  128.     {
  129.         n = recv(socket,m,len,0);
  130.         if(n < 0)
  131.         {
  132.             total = n;
  133.             break;
  134.         }
  135.     else if(n == 0) break;
  136.  
  137.         m += n;
  138.         len -= n;
  139.         total += n;
  140.     }
  141.  
  142.     return(total);
  143. }
  144.  
  145. /****************************************************************************/
  146.  
  147. /* Similar to 'fgets()', but operates on a socket. */
  148. static int
  149. sock_gets(int sock, char *buf, int n)
  150. {
  151.     int result = 0;
  152.     int len;
  153.     char c;
  154.  
  155.     n--;
  156.     while(n > 0)
  157.     {
  158.         len = recv(sock, &c, 1, 0);
  159.         if(len > 0)
  160.         {
  161.             (*buf++) = c;
  162.             result++;
  163.             n--;
  164.  
  165.             if(c == '\n')
  166.                 break;
  167.         }
  168.         else
  169.         {
  170.             break;
  171.         }
  172.     }
  173.  
  174.     (*buf) = '\0';
  175.  
  176.     return(result);
  177. }
  178.  
  179. /****************************************************************************/
  180.  
  181. /* check_emulation: take the remote party's version number as
  182.  * arguments and return our possibly modified version number back
  183.  * (relevant only for clients).
  184.  *
  185.  * Return values:
  186.  * EMULATE_VERSION_OK means we can work together
  187.  *
  188.  * EMULATE_VERSION_TOO_OLD if the other party has too old version
  189.  * which we cannot emulate,
  190.  *
  191.  * EMULATE_MAJOR_VERSION_MISMATCH if the other party has different
  192.  * major version and thus will probably not understand anything we
  193.  * say, and
  194.  *
  195.  * EMULATE_VERSION_NEWER if the other party has never code than we
  196.  * have.
  197.  */
  198. static int
  199. check_emulation(int remote_major, int remote_minor, int *return_major, int *return_minor)
  200. {
  201.     (*return_major) = PROTOCOL_MAJOR;
  202.  
  203.     if(remote_minor < PROTOCOL_MINOR)
  204.         (*return_minor) = remote_minor;
  205.     else
  206.         (*return_minor) = PROTOCOL_MINOR;
  207.  
  208.     if(remote_major < PROTOCOL_MAJOR)
  209.     {
  210.         return(EMULATE_MAJOR_VERSION_MISMATCH);
  211.     }
  212.     else if (remote_major == 1 && remote_minor == 0)
  213.     {
  214.         return(EMULATE_VERSION_TOO_OLD);  /* We no longer support 1.0. */
  215.     }
  216.     else if (remote_major > PROTOCOL_MAJOR || (remote_major == PROTOCOL_MAJOR && remote_minor > PROTOCOL_MINOR))
  217.     {
  218.         /* The remote software is newer than we. If we are the client,
  219.          * no matter - the server will decide. If we are the server, we
  220.          * cannot emulate a newer client and decide to stop.
  221.          */
  222.         return(EMULATE_VERSION_NEWER);
  223.     }
  224.     else
  225.     {
  226.         return(EMULATE_VERSION_OK);
  227.     }
  228. }
  229.  
  230. /****************************************************************************/
  231.  
  232. /* SSH version string exchange */
  233. static int
  234. exchange_identification(struct ssh_protocol_context *spc)
  235. {
  236.     char buf[256], remote_version[256];
  237.     int remote_major, remote_minor, n;
  238.     int my_major, my_minor;
  239.     int result = -1;
  240.     int len;
  241.  
  242.     /* Read other side's version identification. */
  243.     n = sock_gets(spc->spc_Socket, buf, sizeof(buf));
  244.     if(n == 0)
  245.     {
  246.         fprintf(stderr,"SSH: Bad remote protocol identification.\n");
  247.         goto out;
  248.     }
  249.  
  250.     buf[n] = '\n';
  251.  
  252.     /* Check that the versions match.  In future this might accept several
  253.      * versions and set appropriate flags to handle them.
  254.      */
  255.     if(sscanf(buf, "SSH-%d.%d-%[^\n]\n", &remote_major, &remote_minor, remote_version) != 3)
  256.     {
  257.         fprintf(stderr,"SSH: Bad remote protocol version identification.\n");
  258.         goto out;
  259.     }
  260.  
  261.     switch(check_emulation(remote_major, remote_minor, &my_major, &my_minor))
  262.     {
  263.         case EMULATE_VERSION_TOO_OLD:
  264.  
  265.             /* Remote machine has too old SSH software version */
  266.             fprintf(stderr,"SSH: Remote secure shell version %d.%d is too old.\n",remote_major,remote_major);
  267.             goto out;
  268.  
  269.         case EMULATE_MAJOR_VERSION_MISMATCH:
  270.  
  271.             /* Major protocol versions incompatible */
  272.             fprintf(stderr,"SSH: Major secure shell version %d.%d is incompatible with local implementation.\n",remote_major,remote_major);
  273.             goto out;
  274.  
  275.         case EMULATE_VERSION_NEWER:
  276.  
  277.             /* We will emulate the old version. */
  278.             break;
  279.  
  280.         case EMULATE_VERSION_OK:
  281.  
  282.             break;
  283.     }
  284.  
  285.     sprintf(buf, "SSH-%d.%d-%s\n", my_major, my_minor, SSH_VERSION);
  286.  
  287.     len = strlen(buf);
  288.  
  289.     n = send(spc->spc_Socket, buf, len, 0);
  290.     if(n != len)
  291.     {
  292.         fprintf(stderr,"SSH: Error sending protocol identification (%d, %s).\n",errno,strerror(errno));
  293.         result = n;
  294.         goto out;
  295.     }
  296.  
  297.     /* Wait for a public key packet from the server. */
  298.     n = read_packet_and_check_type(spc,SSH_SMSG_PUBLIC_KEY);
  299.     if(n == -2)
  300.     {
  301.         fprintf(stderr,"SSH: Corrupt packet data received.\n");
  302.         result = -1;
  303.         goto out;
  304.     }
  305.     else if (n != 0)
  306.     {
  307.         fprintf(stderr,"SSH: Error reading public key packet (%d, %s).\n",errno,strerror(errno));
  308.         result = n;
  309.         goto out;
  310.     }
  311.  
  312.     result = 0;
  313.  
  314.  out:
  315.  
  316.     return(result);
  317. }
  318.  
  319. /****************************************************************************/
  320.  
  321. /* create session key and ID */
  322. static int
  323. create_keys(struct ssh_protocol_context *spc)
  324. {
  325.     int i, n, len;
  326.     unsigned char session_key[32];
  327.     unsigned char session_id[16];
  328.     unsigned char *RSAblock, *keystr1, *keystr2;
  329.     unsigned char cookie[8];
  330.     R_RSAKey servkey, hostkey;
  331.     MD5Context md5c;
  332.     int result = 0;
  333.  
  334.     memcpy(cookie, spc->spc_PacketIn.body, 8);
  335.  
  336.     i = makekey(spc->spc_PacketIn.body + 8, &servkey, &keystr1);
  337.     makekey(spc->spc_PacketIn.body + 8 + i, &hostkey, &keystr2);
  338.  
  339.     MD5Init(&md5c);
  340.     MD5Update(&md5c, keystr2, hostkey.bytes);
  341.     MD5Update(&md5c, keystr1, servkey.bytes);
  342.     MD5Update(&md5c, cookie, 8);
  343.     MD5Final(session_id, &md5c);
  344.  
  345.     for(i = 0; i < 32; i++)
  346.         session_key[i] = get_random_number() % 256;
  347.  
  348.     len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes);
  349.  
  350.     RSAblock = malloc(len);
  351.     if(RSAblock == NULL)
  352.     {
  353.         /* Out of memory */
  354.         fprintf(stderr,"SSH: Not enough memory for RSA key.\n");
  355.         result = -1;
  356.  
  357.         goto out;
  358.     }
  359.  
  360.     memset(RSAblock, 0, len);
  361.  
  362.     for(i = 0; i < 32; i++)
  363.     {
  364.         RSAblock[i] = session_key[i];
  365.         if(i < 16)
  366.             RSAblock[i] ^= session_id[i];
  367.     }
  368.  
  369.     if(hostkey.bytes > servkey.bytes)
  370.     {
  371.         rsaencrypt(RSAblock, 32, &servkey);
  372.         rsaencrypt(RSAblock, servkey.bytes, &hostkey);
  373.     }
  374.     else
  375.     {
  376.         rsaencrypt(RSAblock, 32, &hostkey);
  377.         rsaencrypt(RSAblock, hostkey.bytes, &servkey);
  378.     }
  379.  
  380.     prepare_packet_header(spc, SSH_CMSG_SESSION_KEY, len + 15);
  381.     spc->spc_PacketOut.body[0] = spc->spc_CipherType;
  382.     memcpy(spc->spc_PacketOut.body + 1, cookie, 8);
  383.     spc->spc_PacketOut.body[9] = (len * 8) >> 8;
  384.     spc->spc_PacketOut.body[10] = (len * 8) & 0xFF;
  385.     memcpy(spc->spc_PacketOut.body + 11, RSAblock, len);
  386.     spc->spc_PacketOut.body[len + 11] = spc->spc_PacketOut.body[len + 12] = 0;
  387.     spc->spc_PacketOut.body[len + 13] = spc->spc_PacketOut.body[len + 14] = 0;
  388.  
  389.     n = write_packet(spc);
  390.     if(n != 0)
  391.     {
  392.         fprintf(stderr,"SSH: Error sending public key packet (%d, %s).\n",errno,strerror(errno));
  393.         result = n;
  394.         goto out;
  395.     }
  396.  
  397.     free(RSAblock);
  398.     RSAblock = NULL;
  399.  
  400.     switch(spc->spc_CipherType)
  401.     {
  402.         case SSH_CIPHER_3DES:
  403.  
  404.             des_set_key(session_key, &spc->spc_Keys[0]);
  405.             des_set_key(session_key + 8, &spc->spc_Keys[1]);
  406.             des_set_key(session_key + 16, &spc->spc_Keys[2]);
  407.  
  408.             break;
  409.  
  410.         case SSH_CIPHER_BLOWFISH:
  411.  
  412.             blowfish_setkey(&spc->spc_EncryptContext, session_key, SSH_SESSION_KEY_LENGTH);
  413.             spc->spc_EncryptContext.biv0 = 0;
  414.             spc->spc_EncryptContext.biv1 = 0;
  415.             spc->spc_DecryptContext = spc->spc_EncryptContext;
  416.  
  417.             break;
  418.     }
  419.  
  420.     spc->spc_UseCipher = TRUE;
  421.  
  422.     /* Wait for key confirmation */
  423.     n = read_packet_and_check_type(spc,SSH_SMSG_SUCCESS);
  424.     if(n == -2)
  425.     {
  426.         fprintf(stderr,"SSH: Corrupt packet data received.\n");
  427.         result = -1;
  428.         goto out;
  429.     }
  430.     if(n != 0)
  431.     {
  432.         fprintf(stderr,"SSH: Remote failed to accept key exchange information (%d, %s).\n",errno,strerror(errno));
  433.         result = n;
  434.         goto out;
  435.     }
  436.  
  437.  out:
  438.  
  439.     if(RSAblock != NULL)
  440.         free(RSAblock);
  441.  
  442.     return(result);
  443. }
  444.  
  445. /****************************************************************************/
  446.  
  447. /* Send password and look at the response. */
  448. static int
  449. send_password(struct ssh_protocol_context *spc,char *password)
  450. {
  451.     int result;
  452.     int n;
  453.  
  454.     n = send_ssh_data(spc,SSH_CMSG_AUTH_PASSWORD,password,strlen(password));
  455.     if(n < 0)
  456.     {
  457.         fprintf(stderr,"SSH: Error sending password (%d, %s).\n",errno,strerror(errno));
  458.         result = n;
  459.         goto out;
  460.     }
  461.  
  462.     n = read_packet_and_check_type(spc,SSH_SMSG_SUCCESS);
  463.     if(n == -2)
  464.     {
  465.         fprintf(stderr,"SSH: Corrupt packet data received.\n");
  466.         result = -1;
  467.         goto out;
  468.     }
  469.     else if (n != 0)
  470.     {
  471.         fprintf(stderr,"SSH: Remote failed to accept password (%d, %s).\n",errno,strerror(errno));
  472.         result = n;
  473.         goto out;
  474.     }
  475.  
  476.     result = 0;
  477.  
  478.  out:
  479.  
  480.     return(result);
  481. }
  482.  
  483. /****************************************************************************/
  484.  
  485. static int
  486. set_maximum_packet_size(struct ssh_protocol_context *spc)
  487. {
  488.     int size = sizeof(spc->spc_InBuf);
  489.     int result = 0;
  490.     int n;
  491.  
  492.     prepare_packet_header(spc,SSH_CMSG_MAX_PACKET_SIZE,4);
  493.  
  494.     spc->spc_PacketOut.body[0] = 0;
  495.     spc->spc_PacketOut.body[1] = 0;
  496.     spc->spc_PacketOut.body[2] = size >> 8;
  497.     spc->spc_PacketOut.body[3] = size & 0xFF;
  498.  
  499.     n = write_packet(spc);
  500.     if(n != 0)
  501.     {
  502.         fprintf(stderr,"SSH: Failed to send packet size configuration packet (%d, %s).\n",errno,strerror(errno));
  503.         result = n;
  504.         goto out;
  505.     }
  506.  
  507.     n = read_packet_and_check_type(spc,SSH_SMSG_SUCCESS);
  508.     if(n == -2)
  509.     {
  510.         fprintf(stderr,"SSH: Corrupt packet data received.\n");
  511.         result = -1;
  512.         goto out;
  513.     }
  514.     else if (n != 0)
  515.     {
  516.         fprintf(stderr,"SSH: Remote failed to accept packet size (%d, %s).\n",errno,strerror(errno));
  517.         result = n;
  518.         goto out;
  519.     }
  520.  
  521.  out:
  522.  
  523.     return(result);
  524. }
  525.  
  526. /****************************************************************************/
  527.  
  528. void
  529. ssh_disconnect(struct ssh_protocol_context *spc)
  530. {
  531.     if(spc != NULL)
  532.     {
  533.         if(spc->spc_Socket != -1)
  534.             CloseSocket(spc->spc_Socket);
  535.  
  536.         free(spc);
  537.     }
  538. }
  539.  
  540. /****************************************************************************/
  541.  
  542. struct ssh_protocol_context *
  543. ssh_connect(char *remote_host_name,int port_number,char *user_name,char *password,int cipher_type)
  544. {
  545.     struct ssh_protocol_context *result = NULL;
  546.     struct ssh_protocol_context *spc;
  547.     struct sockaddr_in sin;
  548.     struct hostent *phe;
  549.     int n;
  550.  
  551.     spc = malloc(sizeof(*spc));
  552.     if(spc == NULL)
  553.     {
  554.         fprintf(stderr,"SSH: Not enough memory for connection information.\n");
  555.         /* Not enough memory */
  556.         goto out;
  557.     }
  558.  
  559.     memset(spc,0,sizeof(*spc));
  560.     spc->spc_Socket = -1;
  561.     spc->spc_CipherType = cipher_type;
  562.     spc->spc_UseCipher = FALSE;
  563.  
  564.     memset(&sin, 0, sizeof(sin));
  565.  
  566.     sin.sin_family = AF_INET;
  567.     sin.sin_port = htons(port_number);
  568.  
  569.     phe = gethostbyname(remote_host_name);
  570.     if(phe != NULL)
  571.     {
  572.         memcpy(&sin.sin_addr, phe->h_addr, phe->h_length);
  573.     }
  574.     else
  575.     {
  576.         sin.sin_addr.s_addr = inet_addr(remote_host_name);
  577.         if(sin.sin_addr.s_addr == -1)
  578.         {
  579.             fprintf(stderr,"SSH: Could not resolve host name '%s'.\n",remote_host_name);
  580.             /* Cannot resolve this host name */
  581.             goto out;
  582.         }
  583.     }
  584.  
  585.     spc->spc_Socket = socket(AF_INET, SOCK_STREAM, 0);
  586.     if(spc->spc_Socket < 0)
  587.     {
  588.         fprintf(stderr,"SSH: Could not create socket (%d, %s).\n",errno,strerror(errno));
  589.         /* Could not create socket */
  590.         goto out;
  591.     }
  592.  
  593.     if(connect(spc->spc_Socket,(struct sockaddr *) &sin, sizeof(sin)) < 0)
  594.     {
  595.         fprintf(stderr,"SSH: Could not connect socket (%d, %s).\n",errno,strerror(errno));
  596.         /* Unable to open connection */
  597.         goto out;
  598.     }
  599.  
  600.     /* Start negotiation on network */
  601.     n = exchange_identification(spc);
  602.     if(n != 0)
  603.         goto out;
  604.  
  605.     /* Create SSH keys */
  606.     n = create_keys(spc);
  607.     if(n != 0)
  608.         goto out;
  609.  
  610.     /* Send the user name. */
  611.     n = send_ssh_data(spc,SSH_CMSG_USER,user_name,strlen(user_name));
  612.     if(n < 0)
  613.     {
  614.         fprintf(stderr,"SSH: Could not send user name (%d, %s).\n",errno,strerror(errno));
  615.         goto out;
  616.     }
  617.  
  618.     n = read_packet(spc);
  619.     if(n == -2)
  620.     {
  621.         fprintf(stderr,"SSH: Corrupt packet data received.\n");
  622.         goto out;
  623.     }
  624.     else if (n < 0)
  625.     {
  626.         fprintf(stderr,"SSH: Could not read response to user name (%d, %s).\n",errno,strerror(errno));
  627.         goto out;
  628.     }
  629.  
  630.     switch(spc->spc_PacketIn.type)
  631.     {
  632.         case SSH_SMSG_SUCCESS:    /* no authentication needed */
  633.  
  634.             break;
  635.  
  636.         case SSH_SMSG_FAILURE:    /* send password */
  637.  
  638.             n = send_password(spc,password);
  639.             if(n != 0)
  640.                 goto out;
  641.  
  642.             break;
  643.  
  644.         default:
  645.  
  646.             /* Invalid packet received. */
  647.             goto out;
  648.     }
  649.  
  650.     n = set_maximum_packet_size(spc);
  651.     if(n != 0)
  652.         goto out;
  653.  
  654.     result = spc;
  655.  
  656.  out:
  657.  
  658.     if(result == NULL)
  659.         ssh_disconnect(spc);
  660.  
  661.     return(result);
  662. }
  663.  
  664. /****************************************************************************/
  665.  
  666. /* Convert raw, encrypted packet to readable structure,
  667.  * return type of packet received.
  668.  */
  669. static int
  670. convert_received_data(struct ssh_protocol_context *spc)
  671. {
  672.     unsigned char *data = spc->spc_InBuf;
  673.     unsigned long crc;
  674.     long len, biglen;
  675.     int i, pad;
  676.     int result;
  677.  
  678.     for(i = len = 0; i < 4; i++)
  679.         len = (len << 8) + data[i];
  680.  
  681.     pad = 8 - (len % 8);
  682.     biglen = len + pad;
  683.  
  684.     spc->spc_PacketIn.length = biglen - 4 - pad;
  685.  
  686.     if(spc->spc_UseCipher)
  687.     {
  688.         switch(spc->spc_CipherType)
  689.         {
  690.             case SSH_CIPHER_3DES:
  691.  
  692.                 des_3cbc_decrypt(data + 4, data + 4, biglen, spc->spc_Keys);
  693.                 break;
  694.  
  695.             case SSH_CIPHER_BLOWFISH:
  696.  
  697.                 blowfish_decrypt_cbc(data + 4, biglen, &spc->spc_DecryptContext);
  698.                 break;
  699.         }
  700.     }
  701.  
  702.     for(i = crc = 0; i < 4; i++)
  703.         crc = (crc << 8) + data[biglen + i];
  704.  
  705.     if(crc == crc32(data + 4, biglen - 4))
  706.     {
  707.         memcpy(spc->spc_PacketIn.data, data + 4, biglen);
  708.  
  709.         spc->spc_PacketIn.type = spc->spc_PacketIn.data[pad];
  710.         spc->spc_PacketIn.body = spc->spc_PacketIn.data + pad + 1;
  711.  
  712.         result = spc->spc_PacketIn.type;
  713.     }
  714.     else
  715.     {
  716.         /* Packet checksum does not match packet data! */
  717.         result = -1;
  718.     }
  719.  
  720.     return(result);
  721. }
  722.  
  723. /****************************************************************************/
  724.  
  725. /* create header for raw outgoing packet */
  726. static void 
  727. prepare_packet_header(struct ssh_protocol_context *spc, int type, int len)
  728. {
  729.     int pad;
  730.  
  731.     len += 5; /* type and CRC */
  732.     pad = 8 - (len % 8);
  733.  
  734.     spc->spc_PacketOut.length = len - 5;
  735.  
  736.     spc->spc_PacketOut.type = type;
  737.     spc->spc_PacketOut.body = spc->spc_PacketOut.data + 4 + pad + 1;
  738. }
  739.  
  740. /****************************************************************************/
  741.  
  742. /* create outgoing packet */
  743. static int
  744. write_packet(struct ssh_protocol_context *spc)
  745. {
  746.     int pad, len, biglen, n, i;
  747.     unsigned long crc;
  748.     int result = 0;
  749.  
  750.     len = spc->spc_PacketOut.length + 5; /* type and CRC */
  751.     pad = 8 - (len % 8);
  752.     biglen = len + pad;
  753.  
  754.     spc->spc_PacketOut.body[-1] = spc->spc_PacketOut.type;
  755.     for(i = 0; i < pad; i++)
  756.         spc->spc_PacketOut.data[i + 4] = get_random_number() % 256;
  757.  
  758.     crc = crc32(spc->spc_PacketOut.data + 4, biglen - 4);
  759.  
  760.     spc->spc_PacketOut.data[biglen + 0] = (unsigned char) ((crc >> 24) & 0xFF);
  761.     spc->spc_PacketOut.data[biglen + 1] = (unsigned char) ((crc >> 16) & 0xFF);
  762.     spc->spc_PacketOut.data[biglen + 2] = (unsigned char) ((crc >>  8) & 0xFF);
  763.     spc->spc_PacketOut.data[biglen + 3] = (unsigned char) ( crc        & 0xFF);
  764.  
  765.     spc->spc_PacketOut.data[0] = (len >> 24) & 0xFF;
  766.     spc->spc_PacketOut.data[1] = (len >> 16) & 0xFF;
  767.     spc->spc_PacketOut.data[2] = (len >>  8) & 0xFF;
  768.     spc->spc_PacketOut.data[3] =  len        & 0xFF;
  769.  
  770.     if(spc->spc_UseCipher)
  771.     {
  772.         switch(spc->spc_CipherType)
  773.         {
  774.             case SSH_CIPHER_3DES:
  775.  
  776.                 des_3cbc_encrypt(spc->spc_PacketOut.data + 4, spc->spc_PacketOut.data + 4, biglen, spc->spc_Keys);
  777.                 break;
  778.  
  779.             case SSH_CIPHER_BLOWFISH:
  780.  
  781.                 blowfish_encrypt_cbc(spc->spc_PacketOut.data + 4, biglen, &spc->spc_EncryptContext);
  782.                 break;
  783.         }
  784.     }
  785.  
  786.     n = send(spc->spc_Socket, spc->spc_PacketOut.data, biglen + 4, 0);
  787.     if(n != biglen + 4)
  788.         result = n;
  789.  
  790.     return(result);
  791. }
  792.  
  793. /****************************************************************************/
  794.  
  795. /* Read a packet with blocking */
  796. static int 
  797. read_packet(struct ssh_protocol_context *spc)
  798. {
  799.     int result = 0;
  800.     int biglen;
  801.     int type;
  802.     int len;
  803.     int n;
  804.     int i;
  805.  
  806.     do
  807.     {
  808.         n = recv_all(spc->spc_Socket, spc->spc_InBuf, 4);
  809.         if(n != 4)
  810.         {
  811.             result = n;
  812.             break;
  813.         }
  814.  
  815.         for(i = len = 0; i < 4; i++)
  816.             len = (len << 8) + spc->spc_InBuf[i];  /* Get packet size */
  817.  
  818.         biglen = len + 8 - (len % 8);
  819.  
  820.         n = recv_all(spc->spc_Socket, spc->spc_InBuf + 4, biglen);  /* Read it */
  821.         if(n != biglen)
  822.         {
  823.             result = n;
  824.             break;
  825.         }
  826.  
  827.         type = convert_received_data(spc);
  828.         if(type < 0)
  829.         {
  830.             result = -2;
  831.             break;
  832.         }
  833.         else if (type == SSH_MSG_DISCONNECT)
  834.         {
  835.             result = -1;
  836.             break;
  837.         }
  838.     }
  839.     while(spc->spc_PacketIn.type == SSH_MSG_DEBUG ||
  840.           spc->spc_PacketIn.type == SSH_MSG_IGNORE);
  841.  
  842.     return(result);
  843. }
  844.  
  845. /****************************************************************************/
  846.  
  847. /* Read a packet and check its type against the one expected. */
  848. static int
  849. read_packet_and_check_type(struct ssh_protocol_context *spc,int type)
  850. {
  851.     int n;
  852.  
  853.     n = read_packet(spc);
  854.     if(n == 0)
  855.     {
  856.         if(spc->spc_PacketIn.type != type) /* Invalid answer from server */
  857.         {
  858.             errno = EACCES;
  859.             n = -1;
  860.         }
  861.     }
  862.  
  863.     return(n);
  864. }
  865.  
  866. /****************************************************************************/
  867.  
  868. /* Send data using the SSH protocol, in several steps if necessary. */
  869. static int
  870. send_ssh_data(struct ssh_protocol_context *spc,int type,void *data,int len)
  871. {
  872.     unsigned char * m = data;
  873.     int total = 0;
  874.     int l,n;
  875.  
  876.     while(len > 0)
  877.     {
  878.         if(len > sizeof(spc->spc_InBuf)-(4+8+1+4))
  879.             n = sizeof(spc->spc_InBuf)-(4+8+1+4);
  880.         else
  881.             n = len;
  882.  
  883.         prepare_packet_header(spc,type,n+4);
  884.  
  885.         spc->spc_PacketOut.body[0] = (n >> 24) & 0xFF;
  886.         spc->spc_PacketOut.body[1] = (n >> 16) & 0xFF;
  887.         spc->spc_PacketOut.body[2] = (n >>  8) & 0xFF;
  888.         spc->spc_PacketOut.body[3] =  n        & 0xFF;
  889.  
  890.         memcpy(&spc->spc_PacketOut.body[4],m,n);
  891.  
  892.         l = write_packet(spc);
  893.         if(l < 0)
  894.         {
  895.             total = l;
  896.             break;
  897.         }
  898.  
  899.         total += n;
  900.         len -= n;
  901.         m += n;
  902.     }
  903.  
  904.     return(total);
  905. }
  906.  
  907. /****************************************************************************/
  908.  
  909. int
  910. ssh_execute_cmd(struct ssh_protocol_context *spc,char *command)
  911. {
  912.     int result;
  913.     int len;
  914.  
  915.     if(command != NULL)
  916.         len = strlen(command);
  917.     else
  918.         len = 0;
  919.  
  920.     if(len > 0)
  921.     {
  922.         result = send_ssh_data(spc,SSH_CMSG_EXEC_CMD,command,len);
  923.         if(result < 0)
  924.             fprintf(stderr,"SSH: Failed to execute command '%s' (%d, %s).\n",command,errno,strerror(errno));
  925.     }
  926.     else
  927.     {
  928.         result = 0;
  929.     }
  930.  
  931.     return(result);
  932. }
  933.  
  934. /****************************************************************************/
  935.  
  936. int
  937. ssh_write(struct ssh_protocol_context *spc, void *data, int len)
  938. {
  939.     int result;
  940.  
  941.     result = send_ssh_data(spc,SSH_CMSG_STDIN_DATA,data,len);
  942.  
  943.     return(result);
  944. }
  945.  
  946. /****************************************************************************/
  947.  
  948. int
  949. ssh_read(struct ssh_protocol_context *spc, void *data, int len)
  950. {
  951.     int total = 0;
  952.  
  953.     if(spc->spc_BytesLeft >= 0)
  954.     {
  955.         unsigned char * m = data;
  956.  
  957.         while(len > 0)
  958.         {
  959.             if(spc->spc_BytesLeft == 0)
  960.             {
  961.                 int payload_size,packet_size,n,i;
  962.  
  963.                 /* Careful there: we don't want to linger in this
  964.                  * routine any longer than is really necessary. If
  965.                  * the previous iteration managed to obtain some
  966.                  * data already, do not attempt to read any more
  967.                  * data as that might cause this routine to block
  968.                  * for no good reason at all.
  969.                  */
  970.                 if(total > 0)
  971.                 {
  972.                     fd_set read_set;
  973.                     struct timeval tv;
  974.  
  975.                     FD_ZERO(&read_set);
  976.                     FD_SET(spc->spc_Socket,&read_set);
  977.                     memset(&tv,0,sizeof(tv));
  978.  
  979.                     /* If there is no additional data waiting,
  980.                      * call it a day and return what we've already
  981.                      * got.
  982.                      */
  983.                     if(select(spc->spc_Socket+1,&read_set,NULL,NULL,&tv) <= 0)
  984.                         break;
  985.                 }
  986.  
  987.                 n = recv_all(spc->spc_Socket,spc->spc_InBuf,4);
  988.                 if(n != 4)
  989.                 {
  990.                     spc->spc_BytesLeft = -1;
  991.  
  992.                     if(n < 0)
  993.                         total = n;
  994.  
  995.                     break;
  996.                 }
  997.  
  998.                 for(i = payload_size = 0; i < 4; i++)
  999.                     payload_size = (payload_size << 8) + spc->spc_InBuf[i];
  1000.  
  1001.                 packet_size = payload_size + (8 - (payload_size % 8));
  1002.  
  1003.                 n = recv_all(spc->spc_Socket,&spc->spc_InBuf[4],packet_size);
  1004.                 if(n != packet_size)
  1005.                 {
  1006.                     spc->spc_BytesLeft = -1;
  1007.  
  1008.                     if(n < 0)
  1009.                         total = n;
  1010.  
  1011.                     break;
  1012.                 }
  1013.  
  1014.                 switch(convert_received_data(spc))
  1015.                 {
  1016.                     case SSH_SMSG_STDERR_DATA:
  1017.  
  1018.                         fwrite(&spc->spc_PacketIn.body[4],spc->spc_PacketIn.length-5,1,stderr);
  1019.                         break;
  1020.  
  1021.                     case SSH_SMSG_STDOUT_DATA:
  1022.  
  1023.                         spc->spc_BytesLeft = spc->spc_PacketIn.length-5;
  1024.                         spc->spc_Ptr = &spc->spc_PacketIn.body[4];
  1025.  
  1026.                         break;
  1027.  
  1028.                     case SSH_SMSG_EXITSTATUS:
  1029.  
  1030.                         prepare_packet_header(spc,SSH_CMSG_EXIT_CONFIRMATION,0);
  1031.                         write_packet(spc);
  1032.  
  1033.                         spc->spc_BytesLeft = -1;
  1034.                         goto out;
  1035.  
  1036.                     case SSH_MSG_DISCONNECT:
  1037.  
  1038.                         spc->spc_BytesLeft = -1;
  1039.                         goto out;
  1040.  
  1041.                     case SSH_SMSG_SUCCESS:
  1042.                     case SSH_MSG_IGNORE:
  1043.  
  1044.                         break;
  1045.  
  1046.                     case -1:
  1047.  
  1048.                         fprintf(stderr,"SSH: Corrupt packet data received.\n");
  1049.                         spc->spc_BytesLeft = -1;
  1050.                         goto out;
  1051.  
  1052.                     default:
  1053.  
  1054.                         break;
  1055.                 }
  1056.             }
  1057.  
  1058.             if(spc->spc_BytesLeft > 0)
  1059.             {
  1060.                 int n;
  1061.  
  1062.                 if(len > spc->spc_BytesLeft)
  1063.                     n = spc->spc_BytesLeft;
  1064.                 else
  1065.                     n = len;
  1066.  
  1067.                 memcpy(m,spc->spc_Ptr,n);
  1068.                 m += n;
  1069.                 total += n;
  1070.                 len -= n;
  1071.  
  1072.                 spc->spc_Ptr += n;
  1073.                 spc->spc_BytesLeft -= n;
  1074.             }
  1075.         }
  1076.     }
  1077.  
  1078.  out:
  1079.  
  1080.     return(total);
  1081. }
  1082.